<?php
/**
 * Created by PhpStorm.
 * User: zero
 * Date: 2018/6/23
 * Time: 11:44
 */

namespace app\index\job;

use think\facade\Cache;
use think\facade\Env;
use think\queue\Job;

class Buying
{
    /**
     * fire方法是消息队列默认调用的方法
     * @param Job            $job      当前的任务对象
     * @param array|mixed    $data     发布任务时自定义的数据
     */
    private  $stock;
    private  $user;
    private  $cache;
    private  $handler;
    public  function  __construct()
    {
        $this->cache = Cache::init();
        $this->handler = $this->cache->handler();
    }
    public function fire(Job $job,$data){

        //读取库存表
        $this->stock = $this->getStock();
        //读取用户表
        $this->user = $this->getUsers();
        // 如有必要,可以根据业务需求和数据库中的最新数据,判断该任务是否仍有必要执行.
        //第二次检测队列用户数，如果超过n人，则缓存写入对应状态,
        //判断用户名是否已经秒杀过，如果已经成功秒杀 这不再进入队列,
        $isJobStillNeedToBeDone = $this->checkDatabaseToSeeIfJobNeedToBeDone($data);
        if(!$isJobStillNeedToBeDone){
            $job->delete();
            print("<info>The user already exists "."</info>\n");
            exit();
        }

        //开始入队
        $isJobDone = $this->doBuyJob($data);

        if ($isJobDone) {
            //如果任务执行成功， 记得删除任务
            $job->delete();
            print("<info> Job has been done and deleted"."</info>\n");

        }else{
            $job->delete();
            $job->failed();
            print("<info>Stock is emtyp ,can't buy again"."</info>\n");
//            if ($job->attempts() > 3) {
//                //通过这个方法可以检查这个任务已经重试了几次了
//                print("<warn>Hello Job has been retried more than 3 times!"."</warn>\n");
//                $job->delete();
//                print("<info>Hello Job has been done and deleted"."</info>\n");
//                // 也可以重新发布这个任务
////                print("<info>Hello Job will be availabe again after 2s."."</info>\n");
////                $job->release(2); //$delay为延迟时间，表示该任务延迟2秒后再执行
//            }else{
//                print("<info>Hello Job will be availabe again after 2s."."</info>\n");
//                $job->release(2); //$delay为延迟时间，表示该任务延迟2秒后再执行
//            }
        }
    }

    /**
     * 有些消息在到达消费者时,可能已经不再需要执行了
     * @param array|mixed    $data     发布任务时自定义的数据
     * @return boolean                 任务执行的结果
     */
    public function checkDatabaseToSeeIfJobNeedToBeDone($data){
        //队列长度，第二次验证,这里的 1 用于代码测试 队列值给1人进，这些数字都可以写个config配置文件直接调用
        //这里为了方便测试直接写上数字
                if($this->handler->lSize('queues:BuyingJobQueue') > 1){
                     $this->cache->set($data['name'],1);
                     return false;
                }
        //检测用户名是否存在，存在则直接结束。。
                   if(in_array($data['name'],$this->user)){
                        return false;
                    }
        return true;
    }

    /**
     * 根据消息中的数据进行实际的业务处理
     * @param array|mixed    $data     发布任务时自定义的数据
     * @return boolean                 任务执行的结果
     */
    private function doBuyJob($data) {
        print_r('doing stock event!');
        //判断库存是否不小于0 如果没库存直接拦截返回false
        if($this->stock['stock'] <= 0){
            $this->cache->set($data['name'],2);
            return false;
        }
        // 根据消息中的数据进行实际的业务处理...
        //如果有库存减1,(这里我们默认减1，可根据用户数量参数来处理),写入数据库
        $this->stock['stock'] = $this->stock['stock']-1;
        //数组转数组类型的格式化字符串
        $stock = var_export($this->stock,true);
        //处理用户事务
        print_r('doing user event');
        $user = $this->user;
        //秒杀成功的用户添加到数组表，用来记录
        array_push($user,$data['name']);
        $user=var_export($user,true);
        //假设处理时间很长
        sleep(3);
        //数据库写入
        file_put_contents(Env::get('app_path').'\data\stock.php',"<?php\n\rreturn \r".$stock.";\r?>");
        file_put_contents(Env::get('app_path').'\data\buyuser.php',"<?php\n\rreturn \r".$user.";\r?>");
        $this->cache->set($data['name'],4);
        return true;
    }

    /**
     * 该方法用于接收任务执行失败的通知，你可以发送邮件给相应的负责人员
     * @param $jobData  string|array|...      //发布任务时传递的 jobData 数据
     */
    public function failed($jobData){
        //send_mail_to_somebody() ;
        print("Warning: Job failed after max retries. job data is :".var_export($jobData,true)."\n");
    }

    //获取库存
    private function  getStock(){
        return require Env::get('app_path').'data\stock.php';
    }
    //获取成功用户表
    private function getUsers(){
       return require_once Env::get('app_path').'\data\buyuser.php';
    }
}